package com.answer.controller;

import cn.hutool.json.JSONUtil;
import com.answer.annotation.AuthCheck;
import com.answer.common.BaseResponse;
import com.answer.common.DeleteRequest;
import com.answer.common.ErrorCode;
import com.answer.constant.UserConstant;
import com.answer.entity.ScoringResult;
import com.answer.entity.User;
import com.answer.exception.BusinessException;
import com.answer.model.dto.scoringResult.ScoringResultAddRequest;
import com.answer.model.dto.scoringResult.ScoringResultQueryRequest;
import com.answer.model.dto.scoringResult.ScoringResultUpdateRequest;
import com.answer.model.vo.ScoringResultVO;
import com.answer.service.ScoringResultService;
import com.answer.service.UserService;
import com.answer.utils.ResultUtils;
import com.answer.utils.ThrowUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 评分结果接口
 */
@RestController
@RequestMapping("/scoringResult")
@Slf4j
public class ScoringResultController {

    @Resource
    private ScoringResultService scoringResultService;

    @Resource
    private UserService userService;

    /**
     * 创建评分结果
     *
     * @param scoringResultAddRequest 评分结果添加请求体，包含创建评分结果所需的信息
     * @param request                  HTTP 请求对象，用于获取当前登录用户信息
     * @return 返回一个包含新创建的评分结果ID的响应对象
     */
    @PostMapping("/add")
    public BaseResponse<Long> addScoringResult(@RequestBody ScoringResultAddRequest scoringResultAddRequest, HttpServletRequest request) {
        // 校验入参是否为空
        ThrowUtils.throwIf(scoringResultAddRequest == null, ErrorCode.PARAMS_ERROR);
        // 将请求体中的数据转换为评分结果实体
        ScoringResult scoringResult = new ScoringResult();
        BeanUtils.copyProperties(scoringResultAddRequest, scoringResult);
        // 处理评分属性列表，转换为JSON字符串存储
        List<String> resultProp = scoringResultAddRequest.getResultProp();
        scoringResult.setResultProp(JSONUtil.toJsonStr(resultProp));
        // 数据校验，确保评分结果信息合法
        scoringResultService.validScoringResult(scoringResult, true);
        // 设置用户ID，填充默认值
        User loginUser = userService.getLoginUser(request);
        scoringResult.setUserId(loginUser.getId());
        // 将评分结果写入数据库
        boolean result = scoringResultService.save(scoringResult);
        // 校验写入是否成功
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回新写入的数据ID
        long newScoringResultId = scoringResult.getId();
        return ResultUtils.success(newScoringResultId);
    }

    /**
     * 删除评分结果
     * <p>
     * 此方法用于删除指定的评分结果。它接受一个删除请求体和一个HttpServletRequest对象作为参数，
     * 通过删除请求体中的ID来确定要删除的评分结果。只有评分结果的所有者或管理员才有权限删除。
     * </p>
     *
     * @param deleteRequest 删除请求体，包含要删除的评分结果的ID
     * @param request       HTTP请求对象，用于获取当前登录用户信息
     * @return 返回一个BaseResponse对象，其中包含一个Boolean值，表示删除操作的结果
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteScoringResult(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        // 校验删除请求是否有效
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取当前登录用户
        User user = userService.getLoginUser(request);
        // 获取待删除的评分结果ID
        long id = deleteRequest.getId();
        // 加载评分结果，确保其存在
        ScoringResult oldScoringResult = scoringResultService.getById(id);
        ThrowUtils.throwIf(oldScoringResult == null, ErrorCode.NOT_FOUND_ERROR);
        // 验证权限：仅本人或管理员可删除
        if (!oldScoringResult.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 执行删除操作
        boolean result = scoringResultService.removeById(id);
        // 校验删除操作结果
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回成功响应
        return ResultUtils.success(true);
    }

    /**
     * 更新评分结果（仅管理员可用）
     *
     * @param scoringResultUpdateRequest 评分结果更新请求体，包含更新所需的评分数据
     * @return 返回更新操作是否成功的布尔值封装在BaseResponse中
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateScoringResult(@RequestBody ScoringResultUpdateRequest scoringResultUpdateRequest) {
        // 参数校验：确保请求体和其ID非空且有效
        if (scoringResultUpdateRequest == null || scoringResultUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 实体类与DTO转换：将请求体转换为ScoringResult实体类
        ScoringResult scoringResult = new ScoringResult();
        BeanUtils.copyProperties(scoringResultUpdateRequest, scoringResult);
        // 处理结果属性列表
        List<String> resultProp = scoringResultUpdateRequest.getResultProp();
        scoringResult.setResultProp(JSONUtil.toJsonStr(resultProp));
        // 数据校验：确保评分结果数据合法
        scoringResultService.validScoringResult(scoringResult, false);
        // 判断评分结果是否存在
        long id = scoringResultUpdateRequest.getId();
        ScoringResult oldScoringResult = scoringResultService.getById(id);
        ThrowUtils.throwIf(oldScoringResult == null, ErrorCode.NOT_FOUND_ERROR);
        // 更新数据库中的评分结果
        boolean result = scoringResultService.updateById(scoringResult);
        // 操作异常处理：若更新失败，则抛出操作错误异常
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 更新成功，返回成功响应
        return ResultUtils.success(true);
    }

    /**
     * 根据id获取评分结果（封装类）
     * 本方法用于通过HTTP GET请求根据指定的评分结果ID获取评分结果的封装类对象
     * 主要包括参数校验、数据查询和封装转换等步骤
     *
     * @param id 评分结果的唯一标识符
     * @return 包含评分结果封装类对象的BaseResponse响应对象
     */
    @GetMapping("/get/vo")
    public BaseResponse<ScoringResultVO> getScoringResultVOById(long id) {
        // 校验输入参数id是否合法
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        // 根据id查询数据库中的评分结果
        ScoringResult scoringResult = scoringResultService.getById(id);
        // 校验查询结果是否存在
        ThrowUtils.throwIf(scoringResult == null, ErrorCode.NOT_FOUND_ERROR);
        // 将评分结果实体转换为封装类对象，并返回成功响应
        return ResultUtils.success(scoringResultService.getScoringResultVO(scoringResult));
    }

    /**
     * 分页获取评分结果列表（仅管理员可用）
     * 该方法允许管理员分页查询评分结果通过传递查询请求参数，从数据库中获取相应的评分结果列表
     *
     * @param scoringResultQueryRequest 包含分页和查询条件的请求对象
     * @return 包含分页评分结果的响应对象
     */
    @PostMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<ScoringResult>> listScoringResultByPage(@RequestBody ScoringResultQueryRequest scoringResultQueryRequest) {
        // 获取请求中的当前页数和每页大小
        long current = scoringResultQueryRequest.getCurrent();
        long size = scoringResultQueryRequest.getPageSize();
        // 调用服务层方法实现分页查询
        Page<ScoringResult> scoringResultPage = scoringResultService.page(new Page<>(current, size),
                scoringResultService.getQueryWrapper(scoringResultQueryRequest));
        // 返回查询结果
        return ResultUtils.success(scoringResultPage);
    }

    /**
     * 分页获取评分结果列表（封装类）
     *
     * @param scoringResultQueryRequest 评分结果查询请求对象，包含分页和筛选条件
     * @return 返回分页的评分结果列表，包括总页数、总记录数和当前页数据等信息
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<ScoringResultVO>> listScoringResultVOByPage(@RequestBody ScoringResultQueryRequest scoringResultQueryRequest) {
        // 获取请求中的当前页码
        long current = scoringResultQueryRequest.getCurrent();
        // 获取请求中的页面大小
        long size = scoringResultQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        Page<ScoringResult> scoringResultPage = scoringResultService.page(new Page<>(current, size),
                scoringResultService.getQueryWrapper(scoringResultQueryRequest));
        // 获取封装类
        return ResultUtils.success(scoringResultService.getScoringResultVOPage(scoringResultPage));
    }

    /**
     * 分页获取当前登录用户创建的评分结果列表
     *
     * @param scoringResultQueryRequest 评分结果查询请求体，包含分页和筛选条件
     * @param request HTTP请求对象，用于获取当前登录用户信息
     * @return 返回分页的评分结果列表，包含评分结果的封装类ScoringResultVO
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<ScoringResultVO>> listMyScoringResultVOByPage(@RequestBody ScoringResultQueryRequest scoringResultQueryRequest,
                                                                           HttpServletRequest request) {
        // 校验参数是否为空
        ThrowUtils.throwIf(scoringResultQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 补充查询条件，只查询当前登录用户的数据
        User loginUser = userService.getLoginUser(request);
        scoringResultQueryRequest.setUserId(loginUser.getId());
        long current = scoringResultQueryRequest.getCurrent();
        long size = scoringResultQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        Page<ScoringResult> scoringResultPage = scoringResultService.page(new Page<>(current, size),
                scoringResultService.getQueryWrapper(scoringResultQueryRequest));
        // 获取封装类
        return ResultUtils.success(scoringResultService.getScoringResultVOPage(scoringResultPage));
    }

    /**
     * 编辑评分结果（给用户使用）
     *
     * @param scoringResultEditRequest 评分结果编辑请求体，包含更新的评分结果信息
     * @param request                   HTTP 请求对象，用于获取当前登录用户信息
     * @return 返回一个布尔值，表示评分结果是否更新成功
     */
    @PostMapping("/edit")
    public BaseResponse<Boolean> editScoringResult(@RequestBody ScoringResultUpdateRequest scoringResultEditRequest, HttpServletRequest request) {
        // 校验请求参数是否合法
        if (scoringResultEditRequest == null || scoringResultEditRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 在此处将实体类和 DTO 进行转换
        ScoringResult scoringResult = new ScoringResult();
        BeanUtils.copyProperties(scoringResultEditRequest, scoringResult);
        // 处理列表属性，将其转换为 JSON 字符串存储
        List<String> resultProp = scoringResultEditRequest.getResultProp();
        scoringResult.setResultProp(JSONUtil.toJsonStr(resultProp));
        // 数据校验
        scoringResultService.validScoringResult(scoringResult, false);
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 判断评分结果是否存在
        long id = scoringResultEditRequest.getId();
        ScoringResult oldScoringResult = scoringResultService.getById(id);
        ThrowUtils.throwIf(oldScoringResult == null, ErrorCode.NOT_FOUND_ERROR);
        // 仅本人或管理员可编辑
        if (!oldScoringResult.getUserId().equals(loginUser.getId()) && !userService.isAdmin(loginUser)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 更新评分结果
        boolean result = scoringResultService.updateById(scoringResult);
        // 如果更新失败，则抛出操作错误异常
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        // 返回更新成功的结果
        return ResultUtils.success(true);
    }
}
